/////////////////////////////////////////////////////////////////////////////
// Copyright(c) 2012-2015 purang All Rights Reserved
// Name:        message_observer.h
// Purpose:
// Author:      syy
// Modified by:
// Created:     2014/7/2 17:54
// RCS-ID:
// Licence:
/////////////////////////////////////////////////////////////////////////////
#ifndef _MESSAGE_OBSERVER_H_
#define _MESSAGE_OBSERVER_H_
#include <assert.h>

#include <list>

#include "../QbLogger.h"
#include "../comdefs.h"
#include "../common_types.h"
#include "../system/atomic32.h"

#ifdef WIN32
#include <combaseapi.h>
#endif

namespace qb {
#define remove_list_item(iter, obj, verb, del)     \
  if (del && obj._ref == 0) {                      \
    for (iter = obj.begin(); iter != obj.end();) { \
      if (!iter->first || iter->second == 0) {     \
        iter = obj.erase(iter);                    \
        continue;                                  \
      }                                            \
      ++iter;                                      \
    }                                              \
  }

#define for_each_list_item(iter, obj, verb) \
  bool del = false;                         \
  obj._ref++;                               \
  while (iter != obj.end()) {               \
    if (iter->first && iter->second > 0) {  \
      verb;                                 \
    } else {                                \
      del = true;                           \
      iter++;                               \
    }                                       \
  }                                         \
  obj._ref--;                               \
  remove_list_item(iter, obj, verb, del)

#define for_each_list(obj, iter, verb) \
  { for_each_list_item(iter, obj, verb); }

#define for_each_list_item_when_true(iter, obj, verb) \
  bool del = false;                                   \
  obj._ref++;                                         \
  while (iter != obj.end()) {                         \
    if (iter->first && iter->second > 0) {            \
      if (verb) {                                     \
        return true;                                  \
      }                                               \
    } else {                                          \
      del = true;                                     \
      iter++;                                         \
    }                                                 \
  }                                                   \
  obj._ref--;                                         \
  remove_list_item(iter, obj, verb, del)

#define for_each_list_when_true(obj, iter, verb) \
  { for_each_list_item_when_true(iter, obj, verb); }

template <class T>
class BList : public std::list<std::pair<T, int32_t>> {
 public:
  BList() : _ref(0) {}
  int32_t _ref;
};

template <typename T>
int32_t RegisterObserver(THIS_ T* observer, BList<T*>& arr) {
  for (typename BList<T*>::iterator it = arr.begin(); it != arr.end(); ++it) {
    if (it->first == observer && it->second > 0) {
      log_info("object already enabled");
      return -1;
    }
  }

  arr.push_back(std::make_pair(observer, 1));

  return 0;
}

template <typename T>
int32_t DeRegisterObserver(THIS_ T* observer, BList<T*>& arr) {
  for (typename BList<T*>::iterator it = arr.begin(); it != arr.end(); ++it) {
    if (it->first == observer) {
      if (arr._ref == 0) {
        arr.erase(it);
        return 0;
      } else if (it->second > 0) {
        it->first = NULL;
        it->second = 0;
        return 0;
      }
    }
  }

  log_info("object already disabled");

  return -1;
}

template <typename T>
int32_t RemoveObserver(THIS_ BList<T*>& arr, bool nonAssert = false) {
  for (typename BList<T*>::iterator it = arr.begin(); it != arr.end();) {
    if (!it->first || it->second == 0) {
      it = arr.erase(it);
      continue;
    }
    ++it;
  }

  // non asset
  if (arr.size() != 0 && nonAssert) {
    arr.clear();
    return 0;
  }

  // check and assert
  if (arr.size() != 0) {
    log_warning("object exist");
    //	assert(0);

    // clear for avoid access security
    arr.clear();
    return -1;
  }
  return 0;
}

}  // namespace qb

#endif  // _MESSAGE_OBSERVER_H_
